import org.w3c.dom.*;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import javax.swing.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.File;
import java.io.IOException;

/**
 * Version: 1.0
 * Autor: Julia und Marco
 * Beschreibung:
 * Mit dieser Klasse wird eine XML Datei über das Spiel geschrieben
 * und / oder eine XML Datei gelesen.
 */

public class XMLController extends DefaultHandler {
    public XMLController() {
    }

    /**
     * Es wird ein neues Document mit der XML Datei erstellt.
     * Danach werden die Infos vom node spieler und Stein ausgelesen.
     *
     * @param path Path zur XML Datei
     * @throws ParserConfigurationException
     * @throws IOException
     * @throws SAXException
     */
    public boolean deserialize(String path) throws ParserConfigurationException, IOException, SAXException {
        File stocks = new File(path);
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
        Document doc = dBuilder.parse(stocks);
        doc.getDocumentElement().normalize();

        NodeList spieler = doc.getElementsByTagName("spieler");
        NodeList steinNodes = doc.getElementsByTagName("Stein");

        if (spieler.getLength() != 0 && steinNodes.getLength() != 0) {
            Damespiel damespiel = new Damespiel(false);
            NamedNodeMap eigenschaften = spieler.item(0).getAttributes();
            String schwarzdran = eigenschaften.getNamedItem("schwarzdran").getNodeValue();
            damespiel.setSpielerSchwarzIstDran(Boolean.parseBoolean(schwarzdran));

            for (int i = 0; i < steinNodes.getLength(); i++) {
                Node item = steinNodes.item(i);
                if (item.getNodeName().equals("Stein")) {
                    boolean korrekt = readAttributes(damespiel, item);
                    if (!korrekt) {
                        damespiel.setVisible(false);
                        return false;
                    }
                }
            }

            return true;
        } else {
            return errorMessage();
        }
    }

    /**
     * Liest die Attribute von den Nodes Spieler. Die Attribute werden dann auf dem
     * Spiel gesetzt.
     *
     * @param damespiel Programm damespiel
     * @param item      das Node von welchem die Attribute gelesen werden sollen
     */
    private boolean readAttributes(Damespiel damespiel, Node item) {
        NamedNodeMap attributes = item.getAttributes();
        Node zeilen = attributes.getNamedItem("zeile");
        Node spalten = attributes.getNamedItem("spalte");
        Node zustände = attributes.getNamedItem("zustand");
        if (zeilen != null && spalten != null && zustände != null) {
            String zeile = zeilen.getNodeValue();
            String spalte = spalten.getNodeValue();
            String zustand = zustände.getNodeValue();
            boolean korrekt = damespiel.setStartAufstellungMitVorgabe(Integer.parseInt(zeile), Integer.parseInt(spalte), zustand);
            return korrekt;
        } else {
            return errorMessage();
        }
    }

    private boolean errorMessage() {
        JOptionPane.showMessageDialog(null, "Kein korrektes XML!", "Falsches XML", JOptionPane.ERROR_MESSAGE);
        return false;
    }

    /**
     * Diese Methode erstellt das XML-File. Damespiel wird das Root Element und an das Root Element werden danach
     * weitere Nodes hinzugefügt. Zum Schluss wird das File geschrieben.
     *
     * @param path im Explorer ausgewählter Pfad wo das XML-File hingeschrieben werden soll.
     * @throws ParserConfigurationException
     */
    public void serialize(String path, SpielFunktionen spielFunktionen) throws ParserConfigurationException {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document document = builder.newDocument();
        Element root = document.createElement("damespiel");
        document.appendChild(root);

        Element spieler = document.createElement("spieler");
        spieler.setAttribute("schwarzdran", Boolean.toString(spielFunktionen.isSpielerSchwarzIstDran()));
        root.appendChild(spieler);

        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 8; j++) {
                creatSteinNode(spielFunktionen, document, root, i, j);
            }
        }

        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        try {
            Transformer transformer = transformerFactory.newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //Formatierung der Datei
            DOMSource source = new DOMSource(document);
            StreamResult result = new StreamResult(new File(path));
            try {
                transformer.transform(source, result);
            } catch (TransformerException e1) {
                e1.printStackTrace();
            }
        } catch (TransformerConfigurationException e1) {
            e1.printStackTrace();
        }
    }

    private void creatSteinNode(SpielFunktionen spielFunktionen, Document document, Element root, int i, int j) {
        Element stein = document.createElement("Stein");
        stein.setAttribute("zeile", Integer.toString(i));
        stein.setAttribute("spalte", Integer.toString(j));
        stein.setAttribute("zustand", spielFunktionen.getZustand(i, j).toString());
        root.appendChild(stein);
    }
}
